package org.opensuse.bs.ui.views;

import java.io.File;
import java.util.Date;
import java.util.Vector;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.part.ViewPart;
import org.opensuse.bs.ui.BSUIPlugin;
import org.opensuse.bs.ui.IBSUIConstants;
import org.opensuse.bs.ui.OSC;
import org.opensuse.bs.ui.model.BSModelElement;
import org.opensuse.bs.ui.model.RemotePackage;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class History extends ViewPart implements ISelectionListener {
	private TableViewer viewer;
	private ITreeSelection selected;
	private String prj;
	private String pkg;
	
	Action refreshAction;
	Action checkoutAction;
	
	private void checkOutRevision() {
		Table table = viewer.getTable();
		int current = table.getSelectionIndex();
		if(current == -1)return;
		final String rev_s = table.getItem(current).getText(0);
		final int rev = Integer.parseInt(rev_s);
		WorkspaceJob checkJob = new WorkspaceJob("Check out revision "+rev_s+" of "+pkg) {
			public IStatus runInWorkspace(IProgressMonitor monitor) {
				IWorkspace workspace = ResourcesPlugin.getWorkspace();
				IWorkspaceRoot workspaceRoot = workspace.getRoot();
				String root = workspaceRoot.getLocation().toOSString();
				File rootPath = new File(root);
				try {
					if (monitor.isCanceled())
						return Status.CANCEL_STATUS;
					String cmd = "co -r "+rev+" "+prj+" "+pkg;
					Vector<String> result = OSC.run(cmd, null, rootPath);
					if(result.isEmpty()) {
						return Status.CANCEL_STATUS;
					}
					IProject p = workspaceRoot.getProject(prj);
					if(!p.exists()) {
						IProjectDescription pd = workspace.newProjectDescription(prj);
						pd.setComment("Build Service");
						pd.setNatureIds(new String[]{"org.opensuse.bs.ui.bsprojectnature"});
						p.create(pd, null);
					}
					if(!p.isOpen())
						p.open(null);
					String path = p.getLocation().toOSString();
					File oldFile = new File(path+"/"+pkg);
					File newFile = new File(path+"/"+pkg+"-revision:"+rev_s);
					if(oldFile.renameTo(newFile)) {
						p.refreshLocal(IResource.DEPTH_INFINITE, null);
					}
				}catch(CoreException e) {
					e.printStackTrace();
				}
				return Status.OK_STATUS;
			}
		};
		checkJob.schedule();
	}
	
	private void updateReviewInfo(ITreeSelection aim) {
		TreePath path = aim.getPaths()[0];
		Object o = path.getLastSegment();
		if(!(o instanceof RemotePackage)) {
			return;
		}
		final Table table = viewer.getTable();
		table.removeAll();
		pkg = ((BSModelElement) o).getName();
		prj = ((BSModelElement) path.getFirstSegment()).getName();
		Job job = new Job("Getting revisions of the package: "+pkg) {
			protected IStatus run(IProgressMonitor monitor) {
				try {
					Document revisionList = OSC.toXML("req -m GET /source/"+prj+"/"+pkg+"/_history");
					if(revisionList == null) {
						return Status.CANCEL_STATUS;
					}
					final NodeList revisions = revisionList.getElementsByTagName("revision");
					if(revisions.getLength() != 0) {
						Display display = viewer.getControl().getDisplay();
						display.asyncExec(new Runnable() {
							public void run() {
								for(int i=revisions.getLength()-1;i>-1;i--) {
									Element revision = (Element) revisions.item(i);
									NodeList version = revision.getElementsByTagName("version");
									NodeList user = revision.getElementsByTagName("user");
									NodeList time = revision.getElementsByTagName("time");
									NodeList comment = revision.getElementsByTagName("comment");
									String[] tmp = new String[5];
									tmp[0] = revision.getAttribute("rev");
									if(version.getLength() == 0) {
										tmp[1] = "";
									}
									else {
										tmp[1] = version.item(0).getTextContent();
									}
									if(user.getLength() == 0) {
										tmp[2] = "";
									}
									else {
										tmp[2] = user.item(0).getTextContent();
									}
									if(time.getLength() == 0) {
										tmp[3] = "";
									}
									else {
										String s = time.item(0).getTextContent();
										Date date = new Date(Long.parseLong(s+"000"));
										tmp[3] = date.toString();
									}
									if(comment.getLength() == 0) {
										tmp[4] = "";
									}
									else {
										tmp[4] = comment.item(0).getTextContent();
									}
									TableItem item = new TableItem(table, SWT.NONE);
									item.setText(tmp);
								}
								viewer.refresh();
							}
						});
					}
				}catch(Exception e) {
					e.printStackTrace();
				}
				return Status.OK_STATUS;
			}
		};
		job.schedule();
	}
	
	public History() {
		selected = null;
	}
	
	public void createPartControl(Composite parent) {
		viewer = new TableViewer(parent, SWT.FULL_SELECTION|SWT.SINGLE
				|SWT.V_SCROLL|SWT.H_SCROLL|SWT.BORDER);
		final Table table = viewer.getTable();
		table.setLinesVisible(true);
		table.setHeaderVisible(true);
		TableColumn[] column = new TableColumn[5];
		for(int i=0;i<5;i++) {
			column[i] = new TableColumn(table, SWT.NONE);
		}
		column[0].setWidth(100);
		column[1].setWidth(100);
		column[2].setWidth(120);
		column[3].setWidth(200);
		column[4].setWidth(200);
		column[0].setText("Revision");
		column[1].setText("Version");
		column[2].setText("Committing User");
		column[3].setText("Committing time");
		column[4].setText("Comment");
		
		getViewSite().getPage().addSelectionListener(this);
		BSUIPlugin plugin = BSUIPlugin.getDefault();
		refreshAction = new Action("Refresh") {
			public void run() {
				if(selected != null) {
					History.this.updateReviewInfo(selected);
				}
			}
		};
		refreshAction.setHoverImageDescriptor(
				plugin.getImageDescriptor(IBSUIConstants.IMG_REFRESH));
		refreshAction.setToolTipText("Refresh BuildResult view " +
				"according to the current selected item in remote view.");
		IActionBars bars = getViewSite().getActionBars();
		IToolBarManager tbm = bars.getToolBarManager();
		tbm.add(refreshAction);
		bars.updateActionBars();
		
		checkoutAction = new Action("Check out the revision") {
			public void run() {
				History.this.checkOutRevision();
			}
		};
		MenuManager mm = new MenuManager();
		Menu m = mm.createContextMenu(table);
		mm.addMenuListener(new IMenuListener() {
			public void menuAboutToShow(IMenuManager manager) {
				manager.add(History.this.checkoutAction);
				manager.add(refreshAction);
			}
		});
		mm.setRemoveAllWhenShown(true);
		table.setMenu(m);
		getSite().registerContextMenu(mm, viewer);
		
		viewer.getControl().addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent event) {
				if(event.keyCode == SWT.F5) {
					History.this.checkOutRevision();
				}
			}
		});
	}
	
	public void setFocus() {
		viewer.getControl().setFocus();
	}
	
	public void selectionChanged(IWorkbenchPart part, ISelection selection) {
		if((part instanceof RemoteView) && (selection instanceof ITreeSelection)) {
			ITreeSelection current = (ITreeSelection) selection;
			if(selected != null && current.equals(selected)) {
				return;
			}
			selected = current;
			updateReviewInfo(current);
		}
	}

}
